<?php

namespace app\common\model;

use app\lib\exception\BaseException;
use think\facade\Cache;
use think\Model;
use app\common\controller\AliSMSController;
use app\common\validate\BaseValidate;
use think\Db;

class User extends Model
{
    // 自动写入时间
    protected $autoWriteTimestamp = true;
    // 发送验证码
    public function sendcode()
    {
        // 获取用户提交手机号码
        $phone = request()->param('phone');
        // 判断是否已经发送过
        if (Cache::get($phone)) throw new BaseException(['msg' => '你的操作太快了', 'errorCode' => 30001]);
        // 生成4位随机数字
        $code = random_int(1111, 9999);
        // 判断是否开启验证码功能
        if (!config('api.aliSMS.isopen')) {
            Cache::set($phone, $code, config('api.aliSMS.expire'));
            throw (new BaseException(['code' => '200', 'msg' => '验证码：' . $code, 'errorCode' => 30005]));
        }
        // 发送验证码
        $res = AliSMSController::SendSMS($phone, $code);
        // 发送成功写入缓存
        if ($res['Code'] == 'OK')  Cache::set($phone, $code, config('api.aliSMS.expire'));
        // 无效号码
        if ($res['Code'] == 'isv.MOBILE_NUMBER_ILLEGAL') throw (new BaseException(['code' => '200', 'msg' => '无效号码', 'errorCode' => 30002]));
        // 触发日限制
        if ($res['Code'] == 'isv.DAY_LIMIT_CONTROL') throw (new BaseException(['code' => '200', 'msg' => '今日发送到上限', 'errorCode' => 30002]));
        // 模板不合法(不存在或被拉黑)
        if ($res['Code'] == 'isv.DAY_LIMIT_CONTROL') throw (new BaseException(['code' => '200', 'msg' => '模板不合法(不存在或被拉黑)', 'errorCode' => 30002]));
        throw (new BaseException(['code' => '200', 'msg' => '验证码：' . $code, 'errorCode' => 30005]));
        // 发送失败
        throw (new BaseException(['code' => '200', 'msg' => '发送失败', 'errorCode' => 30004]));
    }
    // 绑定用户信息表
    public function userinfo()
    {
        return $this->hasOne('Userinfo');
    }
    // 绑定第三方登录
    public function userbind()
    {
        return $this->hasMany('UserBind');
    }

    // 判断用户是否存在
    public function isExist($arr = [])
    {
        if (!is_array($arr)) return false;
        if (array_key_exists('phone', $arr)) { //手机号
            $user = $this->where('phone', $arr['phone'])->find();
            if ($user) $user->logintype = 'phone';
            return $user;
        }
        if (array_key_exists('id', $arr)) { // id
            $user = $this->where('id', $arr['id'])->find();
            return $user;
        }
        if (array_key_exists('email', $arr)) {  // 邮箱
            $user = $this->where('email', $arr['email'])->find();
            if ($user) $user->logintype = 'email';
            return $user;
        }
        if (array_key_exists('username', $arr)) { // 用户名
            $user = $this->where('username', $arr['username'])->find();
            if ($user) $user->logintype = 'username';
            return $user;
        }
        if (array_key_exists('provider', $arr)) {
            $where = [
                'type' => $arr['provider'],
                'openid' => $arr['openid'],
            ];
            $user = $this->userbind()->where($where)->find();
            if ($user) $user->logintype = $arr['provider'];
            return $user;
        }
        return false;
    }

    // 用户手机登录
    public function phonelogin()
    {
        // 获取所有参数
        $params = request()->param();
        // 验证用户是否存在
        $user = $this->isExist(['phone' => $params['phone']]);
        if (!$user) {
            // 用户主表
            $user = self::create([
                'phone' => $params['phone'],
                'username' => $params['phone'],
                'password' => password_hash($params['phone'], PASSWORD_DEFAULT)
            ]);
            $user->userinfo()->create(['user_id' => $user->id]);
            $user->logintype = 'phone';
            return $this->CreateSaveToken($user->toArray());
        }
        // 用户是否被禁用
        $this->checkStatus($user->toArray());

        return $this->CreateSaveToken($user->toArray());
    }
    // 生成并保存Token
    public function CreateSaveToken($arr = [])
    {
        // 生成token
        $token = sha1(md5(uniqid(md5(microtime(true), true))));
        $arr['token'] = $token;
        $expire = array_key_exists('expire_in', $arr) ? $arr['expire_in'] : config('api.token_expire');
        // 保存到缓存
        if (!Cache::set($token, $arr, $expire)) throw new BaseException();
        return $token;
    }
    // 检测用户是否被禁用
    public function checkStatus($arr = [], $isReget = false)
    {
        $status = 1;
        if ($isReget) {
            $userid = array_key_exists('user_id', $arr) ? $arr['user_id'] : $arr['id'];
            // 判断第三方登陆是否绑定手机号码
            if ($userid < 1) return $arr;
            $user = $this->find($userid)->toArray();
            $status = $user['status'];
        } else {
            $status = $arr['status'];
        }
        if ($status == 0) throw (new BaseException(['errorCode' => 20001, 'msg' => '用户已被禁用', 'code' => 200]));
        return $arr;
    }
    // 账号密码登陆
    public function login()
    {
        // 获取所有参数
        $params = request()->param();
        // 验证用户是否存在
        $user = $this->isExist($this->filterUserData($params['username']));
        if (!$user) throw (new BaseException(['code' => 200, 'msg' => '昵称/手机号/用户名错误', 'errorCode' => 20000]));
        // 用户是否被禁用
        $this->checkStatus($user->toArray());

        // 验证密码
        $this->checkPassword($params['password'], $user->password);


        return $this->CreateSaveToken($user->toArray());
    }

    public function filterUserData($data)
    {
        $arr = [];
        if (preg_match('/^1[3456789]\d{9}$/', $data)) {
            $arr['phone'] = $data;
            return $arr;
        }
        if (preg_match('/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/', $data)) {
            $arr['email'] = $data;
            return $arr;
        }
        $arr['username'] = $data;
        return $arr;
    }
    // 验证密码
    public function checkPassword($password, $hash)
    {
        if (!$hash) throw (new BaseException(['code' => 200, 'msg' => '密码错误', 'errorCode' => '20002']));
        if (!password_verify($password, $hash)) throw (new BaseException(['code' => 200, 'msg' => '密码错误', 'errorCode' => '20002']));
        return true;
    }
    // 第三方登陆
    public function otherlogin()
    {
        // 获取所有参数
        $params = request()->param();
        // 解密过程
        // 验证用户是否存在
        $user = $this->isExist(['provider' => $params['provider'], 'openid' => $params['openid']]);
        // 用户不存在创建用户
        $arr = [];
        if (!$user) {
            $user = $this->userbind()->create([
                'type' => $params['provider'],
                'openid' => $params['openid'],
                'nickname' => $params['nickName'],
                'avatarurl' => $params['avatarUrl'],
            ]);
            $user->logintype = $params['provider'];
            $arr = $user->toArray();
            $arr['expires_in'] = $params['expires_in'];
            return $this->CreateSaveToken($arr);
        }
        // 是否被禁用
        $arr = $this->checkStatus($user->toArray(), true);
        $arr['expires_in'] = $params['expires_in'];
        return $this->CreateSaveToken($arr);
    }
    // 验证三方登陆是否绑定手机号
    public function otherLoginIsBindPhone($user = [])
    {
        // 验证是否为账号密码登陆
        if (array_key_exists('type', $user)) {
            if ($user['user_id'] < 0) TApiException('用户没有绑定手机号', 20008, 200);
            return $user['user_id'];
        } else {
            return $user['id'];
        }
    }
    // 退出登陆
    public function loginout()
    {
        if (!Cache::pull(request()->userToken)) TApiException('你已经退出登陆了', 30006);

        return true;
    }
    // 关联文章表
    public function post()
    {
        return $this->hasMany('post');
    }

    // 获取指定用户下的文章列表
    public function getPost()
    {
        $param = request()->param();
        return self::get($param['id'])->post()->with([
            'user' => function ($query) {
                return $query->field('username,id,userpic');
            },
            'images' => function ($query) {
                return $query->field('url')->hidden('pivot');
            }
        ])->where('isopen', 1)->page($param['page'], 10)->select();
    }

    // 获取用户下的所有文章列表
    public function getPostAll()
    {
        $userId = request()->userId;
        $param =  request()->param();
        return self::get($userId)->post()->with([
            'user' => function ($query) {
                return $query->field('username,id,userpic');
            },
            'images' => function ($query) {
                return  $query->field('url')->hidden('pivot');
            }
        ])->page($param['page'], 10)->select();
    }
    // 搜索用户
    public function Search()
    {
        $param = request()->param();
        return $this->where('username', 'like', '%' . $param['keyword'] . '%')->hidden(['password'])->page($param['page'], 10)->select();
    }
    // 验证绑定类型是否冲突
    public function checkBindType($current, $bindtype)
    {
        if ($current == $bindtype) TApiException('绑定类型冲突');
        return true;
    }

    // 用户绑定手机号
    public function bindphone()
    {
        // 获取参数
        $param = request()->param();
        $currentUserInfo = request()->userTokenUserInfo;
        $currentUserId = request()->userId;
        // 当前的登陆类型
        $currentLoginType = $currentUserInfo['logintype'];
        // 验证类型是否冲突
        $this->checkBindType($currentLoginType, 'phone');

        // 查询该手机是否绑定了其他用户
        $binduser = $this->isExist(['phone' => $param['phone']]);
        // 存在
        if ($binduser) {
            // 账号邮箱登录
            if ($currentLoginType == 'username' || $currentLoginType == 'email')
                TApiException('已被绑定', 20006, 200);
            // 第三方登陆
            if ($binduser->userbind()->where('type', $currentLoginType)->find())
                TApiException('已被绑定', 20006, 200);
            // 直接修改
            $userbind = $this->userbind()->find($currentUserInfo['id']);
            $userbind->user_id = $binduser->id;
            if ($userbind->save()) {
                // 更新缓存
                $currentUserInfo['user_id'] = $binduser->id;
                Cache::set(request()->userToken, $currentUserInfo, $currentUserInfo['expires_in']);
                return true;
            }
            TApiException();
        }

        // 不存在
        // 账户密码登陆
        if ($currentLoginType == 'username' || $currentLoginType == 'email') {
            $user = $this->save([
                'phone' => $param['phone']
            ], ['id' => $currentUserId]);
            // 更新缓存
            $currentUserInfo['phone'] = $param['phone'];
            Cache::set(request()->userToken, $currentUserInfo, config('api.token_expire'));
            return true;
        }

        // 第三方登陆
        if (!$currentUserId) {
            // 在user表创建账号
            $user = $this->create([
                'phone' => $param['phone'],
                'username' => $param['phone']
            ]);
            //绑定
            $userbind = $this->userbind->find($currentUserId['id']);
            $userbind->user_id = $user->id;
            if ($userbind->save()) {
                $currentUserInfo['user_id'] = $user->id;
                Cache::set(request()->userToken, $currentUserInfo, $currentUserInfo['expires_in']);
                return true;
            }
            TApiException();
        }
        $user = $this->save([
            'phone' => $param['phone'],
            'username' => $param['phone']
        ], [
            'id' => $currentUserId
        ]);
        return true;
    }

    // 绑定邮箱
    public function bindemail()
    {
        $param = request()->param();
        $currentUserInfo = request()->userTokenUserInfo;
        $currentUserId = request()->userId;
        // 当前的登陆类型
        $currentLoginType = $currentUserInfo['logintype'];
        // 验证类型是否冲突
        $this->checkBindType($currentLoginType, 'email');
        // 查询邮箱是否绑定了用户
        $binduser = $this->isExist(['email' => $param['email']]);
        if ($binduser) {
            if ($currentLoginType == 'username' || $currentLoginType == 'phone')
                TApiException('已经绑定');
        }
    }
    // 修改用户头像
    public function editUserpic()
    {
        // 获取所有参数
        $param = request()->param();
        // 获取用户id
        $userId = request()->userId;
        $image = (new Image())->upload($userId, 'userpic');

        // 修改用户头像
        $user = self::get($userId);
        $user->userpic = getFileUrl($image->url);
        if ($user->save()) return true;
        TApiException();
    }
    // 修改资料
    public function editUserinfo()
    {
        $param = request()->param();
        $userId = request()->userId;
        $user = self::get($userId);
        $user->username = $param['name'];
        $user->save();
        $binduser = $user->userinfo()->find();
        $binduser->allowField(['sex', 'qg', 'job', 'birthday', 'path'])->save($param);
        return true;
    }
    // 修改密码
    public function rePassword()
    {
        // 获取所有参数
        $param = request()->param();
        $userId = request()->userId;
        $userToken =  request()->userToken;
        $currentUser = request()->userTokenUserInfo;
        // 检测账号密码是否正确
        $this->checkPassword($param['oldpassword'], $currentUser['password']);
        $currentUser = self::get($userId);
        if ($currentUser) {
            $currentUser->password = password_hash($param['newpassword'], PASSWORD_DEFAULT);
            $res = $currentUser->save();
            if (!$res) TApiException('修改失败', 20009, 200);
            // 更新缓存
            Cache::set($userToken, $currentUser, config('api.token_expire'));
            return true;
        }
        TApiException();
    }
    // 关联关注表
    public function withFollow()
    {
        return $this->hasMany('follow');
    }
    // 关联粉丝表
    public function fens()
    {
        return $this->belongsToMany('User', 'follow', 'user_id', 'follow_id');
    }
    // 关联关注表
    public function follows()
    {
        return $this->belongsToMany('User', 'follow', 'follow_id', 'user_id');
    }

    public function ToFollow()
    {
        $param = request()->param();
        $followId = $param['follow_id'];
        $userId  = request()->userId;
        if ($followId == $userId) TApiException('非法操作', 10000, 200);
        $arr = ['follow_id' => $followId, 'user_id' => $userId];
        $followModel = $this->get($userId)->withFollow();
        $follow = $followModel->where($arr)->find();
        // 如果存在
        if ($follow) TApiException('你已经关注了', 10000, 200);
        // 如果不存在就新建
        $res =  $followModel->create($arr);
        if (!$res) TApiException();
        return true;
    }

    // 取消关注
    public function unFollow()
    {
        $param = request()->param();
        $userId = request()->userId;
        $followId =  $param['follow_id'];
        if ($userId ==  $followId) TApiException('非法操作');
        $followModel = $this->get($userId)->withFollow();
        $follow = $followModel->where(['follow_id' => $followId])->find();
        if (!$follow) TApiException('该用户已经取消关注了');
        $res = $follow->delete();
        if (!$res) TApiException();
        return true;
    }
    // 获取互关列表
    public function getFriendslist()
    {
        $param = request()->param();
        $userId = request()->userId;
        $page = $param['page'];
        $follows = Db::table('user')->whereIn('id', function ($query) use ($userId) {
            $query->table('follow')->whereIn('user_id', function ($query) use ($userId) {
                $query->table('follow')->where('user_id', $userId)->field('follow_id');
            })->field('user_id');
        })->field('username,userpic,id')->page($page, 10)->select();
        return $follows;
    }
    // 获取粉丝列表
    public function getfenslist()
    {
        $param = request()->param();
        $userId = request()->userId;
        $page = $param['page'];
        $fens = $this->get($userId)->fens()->page($page, 10)->select();
        return $this->filterReturn($fens);
    }
    // 关注列表
    public function getfollowslist()
    {
        $param = request()->param();
        $userId = request()->userId;
        $page = $param['page'];
        $fens = $this->get($userId)->follows()->page($page, 10)->select();
        return $this->filterReturn($fens);
    }


    // 关注和粉丝返回的字端
    public function filterReturn($param = [])
    {
        $arr = [];
        $count = count($param);
        for ($i = 0; $i < $count; $i++) {
            $arr[] = [
                'id' => $param[$i]['id'],
                'username' => $param[$i]['username'],
                'userpic' => $param[$i]['userpic']
            ];
        }
        return $arr;
    }
}
